const { stdout: elog } = require('./erasable-log');

const units = [{
  num: 60,
  name: '秒',
}, {
  num: 60,
  name: '分钟',
}, {
  num: 24,
  name: '小时',
}, {
  num: Number.MAX_VALUE,
  name: '天',
}];

function timespan(time) {
  const _time = [];
  for (let i = 0, n = units.length; i < n; i += 1) {
    const unit = units[i];
    _time.unshift(pad(time % unit.num) + unit.name);
    time = time / unit.num | 0;
    if (time < 1) break;
  }
  return _time.join('');

  function pad(n) {
    return n < 10 ? `0${n}` : n;
  }
}

/**
 * 默认配置
 * @type {Options}
 */
const defaultOptions = {
  valueChar: '#',
  emptyChar: ' ',
  length: 50,
  title: 'load:',
  describe: '',
  total: 0,
  value: 0,
  renderRate: 16, // 至少 16 ms 刷新一次
  format(opts, percent, cells, time) {
    const count = `${percent * opts.total | 0}/${opts.total}`;
    const len = count.length - 1;
    let title = `[${count}] ${opts.describe || ''}\n`;
    title += `[${(100 * percent).toFixed(len).substr(0, len)}%]`;
    if (opts.title) title += ` ${opts.title}`;

    time = time >= 1 && percent > 0 && percent < 1
      ? timespan((time / 1000 | 0) + 1) : '';
    return `${title} [${cells}] ${time}\n`;
  },
};


/**
 * 封装的 Progress Bar 工具
 * @param {Options} opts
 */
function ProgressBar(opts) {
  let _valueFill = '';
  let _emptyFill = '';
  /**
   * 进度条配置
   */
  const _options = Object.assign({}, defaultOptions);

  let _lastRenderTime = 0; // 最后刷新时间

  const _startTime = new Date(); // 任务开始时间

  let _lastAddTime = _startTime;

  let _invalidCount = 0; // 不计数任务数

  const that = {
    /**
     * 初始化
     * @param {Options} opts
     */
    config(opts = {}) {
      for (const k in opts) {
        if (opts[k] !== undefined) {
          _options[k] = opts[k];
        }
      }
      if (opts.length || opts.valueChar || !_valueFill) {
        _valueFill = _fillChar(_options.length, _options.valueChar);
      }
      if (opts.length || opts.emptyChar || !_emptyFill) {
        _emptyFill = _fillChar(_options.length, _options.emptyChar);
      }

      return that;
    },
    /**
     * 设置标题
     * @param {String} val
     */
    title(val) {
      if (val != null) {
        _options.title = val;
      }
      return that;
    },
    /**
     * 设置描述
     * @param {String} val
     */
    describe(val) {
      if (val != null) {
        _options.describe = val;
      }
      return that;
    },
    /**
     * 设置/增加 进度值
     * @param {Number} val 要增加的进度值，默认`1`
     * @param {Boolean} append `false`设置，`true`增加
     */
    value(val = 1, append) {
      if (append) _options.value += val;
      else _options.value = val;
      _lastAddTime = new Date();

      that.render(that.isFull());
    },
    /**
     * 增加进度值
     * @param {Number} time 任务完成时间
     * @param {Number} val 要增加的进度值，默认`1`
     */
    add(val = 1) {
      return that.value(val, true);
    },
    /**
     * 操作总数
     * @param {Number} val
     * @param {Boolean} append
     */
    total(val, append) {
      if (append) _options.total += val;
      else _options.total = val;
      that.render(that.isFull());
    },
    /**
     * 设置无效计数数量（校准进度条剩余时间）
     * @param {Number} val
     */
    invalid(val) {
      if (val === undefined) {
        _invalidCount += 1;
      } else {
        _invalidCount = val;
      }
    },
    /**
     * 刷新进度条
     * @param {Boolean} force 是否强行刷新，否则16ms刷新一次
     */
    render(force) {
      const now = new Date();
      if (!force && now - _lastRenderTime < _options.renderRate) return;
      _lastRenderTime = now;

      const percent = _options.total === 0 ? 0 : (_options.value / _options.total);
      const cellNum = (percent * _options.length | 0);
      let ing = _options.emptyChar;
      if (percent >= 1) ing = '';
      else if ((now / 500 | 0) % 2 === 0) ing = '_';
      const cells = _valueFill.substr(0, cellNum) + ing + _emptyFill.substr(cellNum + 1);
      // 校准时间
      const time = (_lastAddTime - _startTime)
        / (_options.value - _invalidCount)
        * (_options.total - _options.value)
        - (now - _lastAddTime);

      elog(_options.format(_options, percent, cells, time));
    },
    /**
     * 当前值和总数是否相等
     */
    isFull() {
      return _options.value === _options.total;
    },
    /**
     * 结束这个进度条，下次刷新绘制新的进度条
     */
    quit() {
      elog.reset();
    },
  };

  that.config(opts);


  /**
   * 填充值
   * @param {Number} len
   * @param {String} char
   */
  function _fillChar(len, char) {
    return new Array(len).fill(char).join('');
  }

  return that;
}

module.exports = ProgressBar;


/**
 * 进度条配置
 * @typedef Options
 * @property {String} valueChar 进度填充字符
 * @property {String} emptyChar 进度空白字符
 * @property {String} length 进度条长度
 * @property {String} title 标题
 * @property {String} describe 描述
 * @property {Number} total 总值
 * @property {Number} value 进度值
 * @property {Number} renderRate 刷新频率：ms/次
 * @property {(options: Options,
 * percent: Number, cells:String, time: Number) => String} format 刷新频率：ms/次
 * #cells：
 * #time：平均花费时间
 */
// Options
